//Path: ISPD_Contest/sizer-v1.0

#include "optimization.h"
#include "coneSampling.h"
#include "utility.h"
#include <algorithm>
#include "extendedverilogparser.h"
#include "timer_interface.h"
#include "time.h"

#include <ctime>


#include <boost/random/uniform_int.hpp>
#include <boost/random/mersenne_twister.hpp>

#include "validate.cpp"
#include "parser_helper.h"
#include "extendedlibparser.h"
#include "extendedtimingparser.h"
#include "extendedspefparser.h"
#include "extendedsdcparser.h"
#include "extendedverilogparser.h"

using namespace std ;
typedef boost::mt19937 gen;

//global variables, Min
CircuitGraph* graphInPtr;
ExtendedSdcParser* sdcPtr;
ExtendedLibParser* lpPtr;
ExtendedTimingParser* tpPtr;
//vector<string> optList;

int generateRandomNumber(gen& genIn, int end)
{
	boost::uniform_int<int> dist(0, end) ;
  	return dist(genIn) ;
}

void randomizer (CircuitGraph& graphIn)
{
	
	cout << "Start randomizer...." << endl;
	
	int vn = boost::num_vertices(graphIn) ;
	
	gen generator(42u) ;
	generator.seed (static_cast<unsigned int>(std::time(0))) ;
	
	int gateIndex, cellIndex ;
	
	generator.seed (static_cast<unsigned int>(std::time(0))) ;
	
	while (true)
	{
		if   (graphIn[gateIndex].gateType == Combinational)	
			break ;
		gateIndex = generateRandomNumber(generator, vn-1) ;
	}
		
        
	int numberOfCells = graphIn[gateIndex].listOfCells.size() ;
	
	while (true)
	{
		cellIndex = generateRandomNumber(generator, numberOfCells) ;
		if (graphIn[gateIndex].listOfCells[cellIndex] != graphIn[gateIndex].cellName )
			break ;
	}
	
	boost::graph_traits<boostGraph>::vertex_iterator vi, vi_end ;
	
	cout << "Gate index: " << gateIndex <<endl ;
	cout << "Number of gates: " << vn << endl ;
	cout << "Number of cells: " << numberOfCells << endl ;
	cout << "Generate Random Number..." << endl ;
	
	cout << "Ther random cell index is generated..." << cellIndex << endl ;
	
	cout << "Gate (instance name, cell name): ( " << graphIn[ gateIndex ].instanceName
             << ", " << graphIn[ gateIndex ].cellName << ")" << endl ;	
	
	graphIn[gateIndex].cellName = graphIn[gateIndex].listOfCells[cellIndex] ;
        
	cout << "Gate " << graphIn[gateIndex].instanceName << " is sized to " 
             << graphIn[gateIndex].cellName << endl ;
	
			
	cout << "end of randomizer..." << endl ;
	
}

bool lessLeakage(const string &s1, const string &s2)
{
        LibParserCellInfo *LPCI1, *LPCI2;
        LPCI1 = &(lpPtr->mapStandardLibraryCells[s1]);
        LPCI2 = &(lpPtr->mapStandardLibraryCells[s2]);
        
        return (LPCI1->leakagePower < LPCI2->leakagePower);
}

void minLeakage (CircuitGraph& graphIn)
{
        int i,j;
        int numberOfCells;
        LibParserCellInfo *LPCI;
        
        double temp_leakage;
        string selected_cell_name;
        cout << "Choosing minimum leakage cells...." << endl;
        
        int vn = boost::num_vertices(graphIn) ;
        cout << "Number of gates: " << vn << endl ;
        
        for( i = 0; i < vn; i++)
        {
                
                temp_leakage = 10000000.0;//larger enough?
                numberOfCells = graphIn[i].listOfCells.size() ;

                for(j = 0; j < numberOfCells; j++)
                {
                        LPCI = &(lpPtr->mapStandardLibraryCells[graphIn[i].listOfCells[j]]);
                        if(LPCI->leakagePower < temp_leakage)
                        {
                                temp_leakage = LPCI->leakagePower;
                                selected_cell_name = graphIn[i].listOfCells[j];
                        }
                }
                
                if(numberOfCells > 1)//get rid of the DFFs
                        graphIn[ i ].cellName = selected_cell_name;
                
                LPCI = &(lpPtr->mapStandardLibraryCells[ graphIn[ i ].cellName ]);
                
                //sort the cells of same footprint in less leakage order
                std::sort(graphIn[i].listOfCells.begin(),graphIn[i].listOfCells.end(),lessLeakage);                
        }
        
}

bool moreViolation(const int i1, const int i2)
{
        return ((*graphInPtr)[i1].Slew_Violation + (*graphInPtr)[i1].Slack_Violation + (*graphInPtr)[i1].Cap_Violation > 
                (*graphInPtr)[i2].Slew_Violation + (*graphInPtr)[i2].Slack_Violation + (*graphInPtr)[i2].Cap_Violation);
}

void hueSizing (CircuitGraph& graphIn)
{
        int i,j;
        int numberOfCells;
        double threshold = 0.3;
        
        int vn = boost::num_vertices(graphIn) ;
        cout << "Number of gates: " << vn << endl ;
        
        vector<int> optimize_list;

        //first rank the gates based on violation values
        for( i = 0; i < vn; i++)
                optimize_list.push_back(i);
        
        std::sort(optimize_list.begin(),optimize_list.end(),moreViolation);
        
        for( i = 0; i < threshold * vn; i++)
        {
                numberOfCells = graphIn[ optimize_list[i] ].listOfCells.size() ;
                for(j = 0; j < numberOfCells; j++)
                {
                        if(graphIn[ optimize_list[i] ].listOfCells[j] == graphIn[ optimize_list[i] ].cellName 
                           && (j+1) < numberOfCells)
                                graphIn[ optimize_list[i] ].cellName = graphIn[ optimize_list[i] ].listOfCells[j+1]; 
                }
        }
}

bool violationCheck(CircuitGraph& graphIn)
{
        int i = 0;
        LibParserCellInfo *LPCI;
        LibParserCellInfo *LPCI_;
        double T_Output_Cap;
        double Cap_Violation = 0.0;
        double Slack_Violation = 0.0;
        double Slew_Violation = 0.0;
        lpPtr->default_max_transition = 300.0;
       // int vn = boost::num_vertices(graphIn) ;

        vector<LibParserPinInfo>::iterator it;
        boost::graph_traits<CircuitGraph>::vertex_iterator vi, vi_end ;
	boost::graph_traits<CircuitGraph>::out_edge_iterator oi, oi_end ;
        for (boost::tie(vi, vi_end) = boost::vertices(graphIn) ; vi != vi_end ; ++vi)
	{
                
                vertex_descriptor in = (*vi) ;
                graphIn[ i ].Slew_Violation = 0.0;
                graphIn[ i ].Slack_Violation = 0.0;
                graphIn[ i ].Cap_Violation = 0.0;

                if(graphIn[ i ].gateType == 1 || graphIn[ i ].gateType == 0)  
                {
                        i++;
                        continue;
                }
                
                LPCI = &(lpPtr->mapStandardLibraryCells[ graphIn[ i ].cellName ]);
                
                //check the slew violation, for input pins of
                //Combinational and Sequential cells
                //cout<<"Now the max transition time is "<< lpPtr->default_max_transition << endl;

                for(it = LPCI->pins.begin(); it != LPCI->pins.end(); it++)
                        if(it->name != "o")//not the output pins
                        {
                                double temp_violation = 0.0;
                                string tmp_name = graphIn[ i ].instanceName + "/" + it->name;
                                
                                if(tpPtr->PinsTiming[tmp_name].riseTransition > lpPtr->default_max_transition)
                                        temp_violation += tpPtr->PinsTiming[tmp_name].riseTransition - lpPtr->default_max_transition;
                                
                                if(tpPtr->PinsTiming[tmp_name].fallTransition > lpPtr->default_max_transition)
                                        temp_violation += tpPtr->PinsTiming[tmp_name].fallTransition - lpPtr->default_max_transition;
                                
                                if(temp_violation != 0.0)
                                {
                                        cout<<"the instance name is "<< graphIn[ i ].instanceName <<endl;
                                }
                                graphIn[ i ].Slew_Violation += temp_violation;                                
                                Slew_Violation += temp_violation;
                        }
                
                //check the slack violation, for sequential gates
                if(graphIn[ i ].gateType == 3)
                {
                        for(it = LPCI->pins.begin(); it != LPCI->pins.end(); it++)
                                if(it->name != "o" && it->name != "ck")//not the output pins
                                {
                                        double temp_violation = 0.0;
                                        string tmp_name = graphIn[ i ].instanceName + "/" + it->name;
                                        
                                        if(tpPtr->PinsTiming[tmp_name].riseSlack < 0)
                                                temp_violation += abs(tpPtr->PinsTiming[tmp_name].riseSlack);
                                        
                                        if(tpPtr->PinsTiming[tmp_name].fallSlack < 0)
                                                temp_violation += abs(tpPtr->PinsTiming[tmp_name].fallSlack);
                                        
                                        //for sequential circuit, should be
                                        //only one net connect to DFF input
                                        
                                        //graphIn[ i ].Slack_Violation += temp_violation;
                                        Slack_Violation += temp_violation;
                                }
                }
                
                //check the output cap violation
                T_Output_Cap = 0.0;
                for ( boost::tie(oi, oi_end) = boost::out_edges(in, graphIn) ; oi != oi_end ; ++oi )
                {
                        //finding the pin connect to PI, for driver,
                        //instance name and pin name and cell name are same
                        
                        //check the slack and slew violation, for POs
                        if(graphIn[target((*oi), graphIn)].gateType == 1)//is PO
                        {
                                double temp_slack_violation = 0.0;
                                double temp_slew_violation = 0.0;
                                        
                                if(tpPtr->PortsTiming[graphIn[(*oi)].netName].riseSlack < 0)
                                        temp_slack_violation += abs(tpPtr->PortsTiming[graphIn[(*oi)].netName].riseSlack);
                                
                                if(tpPtr->PortsTiming[graphIn[(*oi)].netName].fallSlack < 0)
                                        temp_slack_violation += abs(tpPtr->PortsTiming[graphIn[(*oi)].netName].fallSlack);
                                
                                if(tpPtr->PinsTiming[graphIn[(*oi)].netName].riseTransition > lpPtr->default_max_transition)
                                        temp_slew_violation += tpPtr->PinsTiming[graphIn[(*oi)].netName].riseTransition - lpPtr->default_max_transition;
                                
                                if(tpPtr->PinsTiming[graphIn[(*oi)].netName].fallTransition > lpPtr->default_max_transition)
                                        temp_slew_violation += tpPtr->PinsTiming[graphIn[(*oi)].netName].fallTransition - lpPtr->default_max_transition;
                                
                                Slack_Violation += temp_slack_violation;
                                Slew_Violation += temp_slew_violation;

                                //for PO, the violation comes from its
                                //fan-in gates
                                graphIn[source((*oi), graphIn)].Slack_Violation += temp_slack_violation;                                
                                graphIn[source((*oi), graphIn)].Slew_Violation += temp_slew_violation;                                
                        }
                                                
                        //net name should be unique
                        T_Output_Cap += graphIn[(*oi)].netParasiticLoad;
                        
                        LPCI_ = &(lpPtr->mapStandardLibraryCells[graphIn[target((*oi), graphIn)].cellName]); 
                        //cout<<"Target Pin name is "<<graphIn[(*oi)].targetPinName<<endl;
                        
                        for( it = LPCI_->pins.begin(); it != LPCI_->pins.end(); it++ )
                                if(it->name == graphIn[(*oi)].targetPinName)
                                        break;
                        
                        if(it != LPCI_->pins.end())
                                T_Output_Cap += (*it).capacitance;
                        else//should go back to the spec file for the output load
                                T_Output_Cap += sdcPtr->outputs_load[graphIn[(*oi)].netName];
                }
                
                for( it = LPCI->pins.begin(); it != LPCI->pins.end(); it++ )
                        if(it->name == "o")
                                break;
                
                if(it == LPCI->pins.end())
                        cout<<"No Way"<<endl;
                
                if( (*it).maxCapacitance < T_Output_Cap){
                        Cap_Violation += T_Output_Cap - (*it).maxCapacitance;
                        graphIn[ i ].Cap_Violation += T_Output_Cap - (*it).maxCapacitance;
                }

                i++;
        }
        
        /*//for testing
        for( i = 0; i < vn; i++)
        {
                cout<<"Cell Name: "<< graphIn[ i ].cellName <<endl;
                cout<< "Slack Violation is  "<< graphIn[ i ].Slack_Violation << "\t"
                    << "Slew Violation is  "<< graphIn[ i ].Slew_Violation << "\t"
                    << "Cap Violation is  "<< graphIn[ i ].Cap_Violation << endl;
        }
        */

        cout<< "Slew Violation is " << Slew_Violation <<endl;
        cout<< "Slack Violation is " << Slack_Violation << endl;
        cout<< "Cap Violation is " << Cap_Violation << endl;
        double Total_Violation = Slew_Violation + Slack_Violation + Cap_Violation;
        cout<< "Total Violation is " << Total_Violation << endl;
        
        if(Total_Violation > 0.00001)
                return false;
        
        return true;
}

int main (int argc, char* argv[]) 
{
        
	string contest_dir, benchmark_dir ;
	
	contest_dir = getenv ( "ISPD_CONTEST_ROOT" ) ; 
	benchmark_dir = getenv ( "ISPD_CONTEST_BENCHMARK" ) ;
        cout<<"Benchmark directory is "<<benchmark_dir<<endl;
        
	clock_t startReadStandardLibraryCell = clock() ;
	// 1. Read Standard Library Cell
	//------------------------------------------------------------------------------------
	string standardLibFile = contest_dir+"/lib/contest.lib" ;
	cout << "Start reading standard library cell ( " <<  standardLibFile << " )" << endl ;
	ExtendedLibParser lp (standardLibFile) ;
	lp.readStandardLibraryCell () ;
        lpPtr = &lp;
        cout<<"Default Max Transition is " << lpPtr->default_max_transition <<endl;

        // 2. Read Sdc File
        string sdcFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".sdc" ;
        ExtendedSdcParser sdcp(sdcFile);
        sdcp.readSdcFile();
        sdcPtr = &sdcp;
	//------------------------------------------------------------------------------------
	clock_t endReadStandardLibraryCell = clock() ;
	
	
	clock_t startReadSpef = clock() ;
	// 3. Read Parasitic Load
	//-----------------------------------------------------------------------------------
	string spefFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".spef" ;
	cout << "Start reading parasitic load from " << spefFile << endl ;
	ExtendedSpefParser sp (spefFile) ;
	sp.readSpefFile () ;
	//-----------------------------------------------------------------------------------
	clock_t endReadSpef = clock() ;
	
	// 4. Initialize the circuit graph
	//-----------------------------------------------------------------------------------
	cout << "The graph is initialized..." << endl;
	CircuitGraph inputCircuit ;
        graphInPtr = &inputCircuit;
	//-----------------------------------------------------------------------------------
        
	
	clock_t startReadVerilog = clock() ;
	// 5. Read Verilog File
	//-----------------------------------------------------------------------------------
	string verilogFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".v" ;
	cout << "Start reading verilog file " << verilogFile << endl ;
	ExtendedVerilogParser vp (verilogFile) ;
	vp.readVerilogFile(inputCircuit, lp.mapStandardLibraryCells) ;
	cout << "End reading verilog file..." << endl ;
	//-----------------------------------------------------------------------------------
	clock_t endReadVerilog = clock() ;
	
	// 6. Udate edges in graph
	//-----------------------------------------------------------------------------------
	inputCircuit.updateConnectivity(vp.verilogConnectivity, sp.mapNetParasiticLoads) ;
	//-----------------------------------------------------------------------------------
	
	//inputCircuit.printGateProperty < string, gateProperty> (&gateProperty::cellName) ;
	
	cout << "The graph is ready for optimization..." << endl ;
        cout.precision(3) ;
	double leakageBefore = inputCircuit.accumTotalLeakage(lp.mapStandardLibraryCells) ;
	//double leakageBefore = 0.0;
	clock_t startOptimization = clock() ;
        
        /*Amir's part......................*/
        //6. Read .sdc file                                                                                                      
        // -----------------------------------------------------------------------------------
        //string sdcFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".sdc" ;
        cout << "Start reading sdc file " << sdcFile << endl ;
        ExtendedSdcParser sdp (sdcFile) ; 
        string clockName ;
        string clockPort ;
        double period ;
        
        sdp.read_clock (clockName, clockPort, period) ;
        sdp.readInputDelays () ;
        sdp.readInputDrivers () ;
        sdp.readOutputDelays () ;
        sdp.readOutputLoads () ;
        sdp.updateOutputCap(inputCircuit) ;
        sdp.updateInputTime (inputCircuit, lp) ;
        //----------------------------------------------------------------------------------
        //cout << "The graph is ready for optimization..." << endl ;
        // Find the range of Output Capacitance for each gate and store
        // that in a file                                            
        //----------------------------------------------------------------------------------------------                          
        string capFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + "_capRange.txt" ;
        ofstream outCapacitance(capFile.c_str()) ;
        StoreOutCapacitance storeFunc ; 
        inputCircuit.updateMinMaxOutputCap (lp, storeFunc, outCapacitance, true) ;
        //----------------------------------------------------------------------------------------------                          

        // fill each node in the circuit with library cells that have no
        // output violations                                        
        inputCircuit.fillNoCapViolationCells (lp) ;
        /*Amir's part......................*/

	// 7. Initialize optimization, 
        // (1) size all cells to maximum power saving
	
	Optimization op (contest_dir, benchmark_dir, 1, &minLeakage) ;
	
	cout << "Call updater function..." << endl ;
	op.updateCellType (inputCircuit) ;
        
	cout << "Make the sizer file... " << endl ;
	op.buildSizerFile (inputCircuit, false) ;
                
        //(2) delete the timing file first, otherwise will have interface error 
        string timingFile = contest_dir + "/" + benchmark_dir + "/" + benchmark_dir + ".timing" ;
	//ifstream infile(timingFile.c_str());
        //if(infile)
        //remove( timingFile.c_str() );
        
        cout << "Call timer..." << endl ;
        op.callTimer() ;
        cout << "Finished!!!" << endl ;
        clock_t endOptimization = clock() ;
        
        //(3) parsing the timing file for the first time 
        ExtendedTimingParser tp (timingFile) ;
        tp.readTimingFile();
        tpPtr = &tp;
        //tp.closeTimingFile();
        
        //(4) divided into cones and optimize each        
        Cone myCone;
        myCone.number_dffs(inputCircuit);
        myCone.TpPtr = &tp;
        myCone.LpPtr = &lp;
        myCone.clear_flag(inputCircuit);
        //myCone.topo_order_whole_graph(inputCircuit); 
        myCone.topo_order_dffs(inputCircuit); 
        myCone.clear_flag(inputCircuit);
        myCone.form_cones(inputCircuit);
        myCone.reset_cones();
        myCone.clear_flag(inputCircuit);
        
        string temp_dir = contest_dir + "/" + benchmark_dir;
        cout<<temp_dir<<endl;
        violation_ctrl MyVc(benchmark_dir,standardLibFile);
        
        //may needs many rounds to reach a zero-violation solution
        int cone_id, flag, count = 0;
        double temp_violation;
        std::vector<vertex_descriptor> critical_gates;
        std::vector<vertex_descriptor>::iterator it;
        std::map<double, vertex_descriptor> RankMap;//use a map for rank
        std::map<double, vertex_descriptor>::iterator it_RM;//use a map for rank
        /*
        for(cone_id = 0; cone_id < myCone.cones.size(); cone_id++)
        {
                
                if(myCone.cones[cone_id].gate_ids.size() == 0)
                        myCone.cones[cone_id].done = 1;
                
                if(myCone.cones[cone_id].done == 1)
                        continue;
                
                cout<<"Cone "<< cone_id << " 's gate number is "
                    << myCone.cones[cone_id].gate_ids.size() <<endl;
                
                while(1){
                        
                        flag = 0;
                        temp_violation = 0.0;
                        critical_gates.clear();
                        RankMap.clear();
                        
                        cout<<"Optimizing Cone "<< cone_id <<endl;
                        //special case for gates number in a cone less than minimum
                        //dealing amount per itr.

                        //first push in the DFF, then extract the critical path.
                        //cout<<"Critical Path Extraction Begins......."<<endl;
                        myCone.cones[cone_id].critical_path.clear();
                        myCone.cones[cone_id].critical_path.push_back(myCone.cones[cone_id].gate_idx);
        
                        vertex_descriptor v = myCone.cones[cone_id].gate_idx;
                        while(myCone.extract_critical_path(v, cone_id, inputCircuit) == false);
                        //std::cin.get();
                        cout<<"Critical path is...."<<endl; 
                        for(it = myCone.cones[cone_id].critical_path.begin(); it != myCone.cones[cone_id].critical_path.end(); it++)
                                cout<<*it<<"\t";
                        cout<<endl;

                        //cout<<"Critical Gates Chosen Begins......."<<endl;
                        //Choose the one that is closest to the PI if it does lead to
                        //slew violation, then begin the general choosing procedure
                        CircuitGraph::adjacency_iterator vi, vi_end;
                        
                        if(inputCircuit[myCone.cones[cone_id].critical_path.back()].Slew_Violation > 0.0 && inputCircuit[myCone.cones[cone_id].critical_path.back()].visited == 0)
                                critical_gates.push_back(myCone.cones[cone_id].critical_path.back());
                
                        for(it = myCone.cones[cone_id].critical_path.begin(); it != myCone.cones[cone_id].critical_path.end(); it++)
                        {
                                temp_violation = inputCircuit[(*it)].Slew_Violation + inputCircuit[(*it)].Slack_Violation;
                                RankMap[temp_violation] = *it;
                        
                                if(inputCircuit[(*it)].visited == 0)//still gates that are not sized
                                        flag++;
                        }
                        
                        if(myCone.cones[cone_id].gate_ids.size() <= myCone.Fixed_Gates_Per_Itr)
                        {
                                myCone.cones[cone_id].critical_gates = myCone.cones[cone_id].gate_ids;
                                for(it = myCone.cones[cone_id].critical_gates.begin(); it != myCone.cones[cone_id].critical_gates.end(); it++)
                                {
                                        inputCircuit.sampleGateDelay (*it, *(myCone.LpPtr), myCone.ReducedCellSize, inputCircuit[*it].ReducedCellSet);
                                        //inputCircuit.sampleGateAngle (*it, *(myCone.LpPtr), myCone.ReducedCellSize, inputCircuit[*it].ReducedCellSet);
                                }
                        }
                        else
                        {
                                for(it_RM = RankMap.begin(); it_RM != RankMap.end(); it_RM++)
                                {
                                        //if more unsized than processed per itr, choose among
                                        //these gates
                                        if(flag != 0)
                                        {
                                                if(flag >= myCone.Fixed_Gates_Per_Itr)
                                                {
                                                        if(inputCircuit[it_RM->second].visited == 0) 
                                                                critical_gates.push_back(it_RM->second);
                                                }
                                                else
                                                {
                                                        critical_gates.push_back(it_RM->second);
                                                        if(inputCircuit[it_RM->second].visited == 1)
                                                                flag++;
                                                }
                                        }
                                        else
                                        {
                                                cout<<"All the gates in this cone has been sized! We still need more rounds to get no violation."<<endl;
                                                critical_gates.push_back(it_RM->second);
                                        }
                        
                                        inputCircuit.sampleGateDelay (it_RM->second, *(myCone.LpPtr), myCone.ReducedCellSize, inputCircuit[it_RM->second].ReducedCellSet);
                                        //inputCircuit.sampleGateAngle (it_RM->second, *(myCone.LpPtr), myCone.ReducedCellSize, inputCircuit[it_RM->second].ReducedCellSet);
                                        if(critical_gates.size() == myCone.Fixed_Gates_Per_Itr)
                                                break;
                                }
                                
                                std::swap(myCone.cones[cone_id].critical_gates, critical_gates);
                        }
                        
                        
                        myCone.sample_procedure(cone_id, inputCircuit);
                        cout << "Make the sizer file... " << endl ;
                        op.buildSizerFile (inputCircuit, false) ;
                        cout << "Call timer..." << endl ;
                        op.callTimer() ;
                        cout << "Finished!!!" << endl ;
                        tp.updateTimingFile(timingFile);
                        MyVc.check_violations();
                        
                        string temp_name = inputCircuit[myCone.cones[cone_id].gate_idx].instanceName 
                                + "/" + "d";
                        
                        double temp = 0.0;
                        if(myCone.TpPtr->PinsTiming[temp_name].riseSlack < 0)
                                temp += abs(myCone.TpPtr->PinsTiming[temp_name].riseSlack);
                        
                        if(myCone.TpPtr->PinsTiming[temp_name].fallSlack < 0)
                                temp += abs(myCone.TpPtr->PinsTiming[temp_name].fallSlack);
                        
                        if(myCone.TpPtr->PinsTiming[temp_name].riseTransition > 300)
                                temp += 300 - abs(myCone.TpPtr->PinsTiming[temp_name].riseTransition);
                        
                        if(myCone.TpPtr->PinsTiming[temp_name].fallTransition > 300)
                                temp += 300 - abs(myCone.TpPtr->PinsTiming[temp_name].fallTransition);
                        
                        if(temp = 0.0)
                        {
                                cout<<"Cone "<< cone_id <<" is done!!!"<<endl;
                                myCone.cones[cone_id].done == 1;
                                break;
                        }
                        
                        //std::cin.get();
                }
                
        }
        */
        
        // while(!MyVc.check_violations()){ 
        //         cout<<"Optimization Round "<< count <<endl;
        //         myCone.sampling(inputCircuit);
        //         cout << "Call updater function..." << endl ;
        //         //op.updateCellType (inputCircuit) ;
        //         cout << "Make the sizer file... " << endl ;
        //         op.buildSizerFile (inputCircuit, false) ;
        //         cout << "Call timer..." << endl ;
        //         op.callTimer() ;
        //         cout << "Finished!!!" << endl ;
        //         tp.updateTimingFile(timingFile);
        //         cout<<"My Checker.......... "<<endl;
        //         violationCheck(inputCircuit);
        //         cout<<"Provided Checker.......... "<<endl;
        //         MyVc.check_violations();
        //         count++;
        // }
        
        //finished and reporting
	cout << "Gate after optimization: " << endl;
	//inputCircuit.printGateProperty < string, gateProperty> (&gateProperty::cellName) ;
	
	cout.precision(3) ;
	cout << "The leakage power is (before optimization): " << leakageBefore << endl ;
	cout << "The leakage power is (after optimization): " << inputCircuit.accumTotalLeakage(lp.mapStandardLibraryCells) << endl ;
	
	//printEdgesProperty <string, netProperty> (sample, &netProperty::netName) ;
        
	cout.precision(5) ;
	double timeStandard = (double)(endReadStandardLibraryCell - startReadStandardLibraryCell) / (double)CLOCKS_PER_SEC ;
	double timeSpef = (double)(endReadSpef - startReadSpef) / (double)CLOCKS_PER_SEC ;
	double timeVerilog = (double)(endReadVerilog - startReadVerilog) / (double)CLOCKS_PER_SEC ; 
	double timeOptimization = (double)(endOptimization - startOptimization) / (double)CLOCKS_PER_SEC ;
	
	cout << "--------------Run time---------------" << endl ;
	cout << "Reading Standard Library Cell: " <<  timeStandard << endl;
	cout << "Reading SPEF: " <<  timeSpef << endl;
	cout << "Reading Verilog: " << timeVerilog << endl;
	cout << "Optimization: " << timeOptimization << endl;
	cout << "Total: " << timeStandard + timeSpef + timeVerilog + timeOptimization << endl ;
	cout << "-------------------------------------" << endl ;
        
           
        return 0;
}
